package com.flyduck.vueshop.common.redis.aspect;

import com.flyduck.vueshop.common.core.lang.Result;
import com.flyduck.vueshop.common.redis.annotation.NoRepeatSubmit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * RepeatSubmitAspect
 * </p>
 *
 * @author flyduck
 * @since 2024-05-22
 */
@Aspect
@Component
public class RepeatSubmitAspect {

    @Resource
    private RedissonClient redissonClient;

    @Pointcut("@annotation(noRepeatSubmit)")
    public void pointCut(NoRepeatSubmit noRepeatSubmit){
    }

    @Around("pointCut(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint pjp,NoRepeatSubmit noRepeatSubmit) throws Throwable {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        String token = request.getHeader("token");
        String path = request.getServletPath();
        //用户身份 + 请求接口路径作为key
        String key = token + path;

        RLock rLock = redissonClient.getLock(key);

        //只获取锁，不释放锁，等lockTime到了自动释放锁，所以在lockTime范围时间内都无法重复提交
        boolean isSuccess = rLock.tryLock(0, noRepeatSubmit.lockTime(), TimeUnit.SECONDS);
        if (isSuccess) {
            //获取锁成功，执行方法
            return pjp.proceed();
        }else {
            return Result.fail("重复提交，请稍后重试！");
        }

    }
}
